package api

import (
	"errors"
	"fmt"
	"gitee.com/gopher2011/bookman/app/dao"
	"github.com/dgrijalva/jwt-go"
	"github.com/gin-gonic/gin"
	"net/http"
	"strings"
)

var (
	TokenExpired     = errors.New(" Token过期了!")
	TokenNotValidYet = errors.New(" Token未激活")
	TokenMalformed   = errors.New("这不是Token")
	TokenInvalid     = errors.New("无法处理此Token")
)

type JWT struct {
	SigningKey []byte //token 的签名
}

func NewJwt() *JWT {
	return &JWT{
		[]byte(dao.Cfg.JWT.SigningKey), //从配置文件中读取SigningKey
	}
}

// 创建一个 token 参数 JwtClaims 是需要被token保护的信息
func (j *JWT) CreateToken(claims JwtClaims) (string, error) {
	token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
	return token.SignedString(j.SigningKey)
}

// 解析token
func (j *JWT) ParseToken(tokenStr string) (*JwtClaims, error) {
	token, err := jwt.ParseWithClaims(tokenStr, &JwtClaims{}, func(token *jwt.Token) (i interface{}, e error) {
		return j.SigningKey, nil
	})
	if err != nil {
		if v, ok := err.(*jwt.ValidationError); ok {
			if v.Errors&jwt.ValidationErrorMalformed != 0 {
				return nil, TokenMalformed
			} else if v.Errors&jwt.ValidationErrorExpired != 0 {
				// token过期了
				return nil, TokenExpired
			} else if v.Errors&jwt.ValidationErrorNotValidYet != 0 {
				return nil, TokenNotValidYet
			} else {
				return nil, TokenInvalid
			}
		}
	}
	if token != nil {
		if claims, ok := token.Claims.(*JwtClaims); ok && token.Valid {
			return claims, nil
		}
		return nil, TokenInvalid
	} else {
		return nil, TokenInvalid
	}
}

func Prepare() gin.HandlerFunc {
	return func(c *gin.Context) {
		//限定请求的微信小程序的appid
		appId := dao.Cfg.Server.AppId
		if appId != "" && dao.Cfg.Server.LimitReferer && dao.Cfg.Server.RunMode != "dev" {
			prefix := fmt.Sprintf("https://servicewechat.com/%v/", appId)
			if !strings.HasPrefix(strings.ToLower(c.Request.Referer()), prefix) {
				c.JSON(http.StatusNotFound, "not found")
			}
		}
		BaseAuth.Token = c.Request.Header.Get("Authorization")
		BaseAuth.Version = c.Request.Header.Get("x-version")
		uid, _ := dao.BookDao.GetByToken(BaseAuth.Token)
		// 不允许游客访问，则除了部分涉及登录的API外，一律提示先登录
		if !dao.Cfg.Server.AllowVisitor && uid == 0 {
			c.JSON(http.StatusBadRequest, messageMustLogin)
		}
		// 如果不允许注册，则不允许用户访问注册相关的接口，其他接口可以访问
		if !dao.Cfg.Server.AllowRegister {
			c.JSON(http.StatusBadRequest, messageForbidRegister)
		}
	}
}

// JWT 鉴权
func JWTAuth()gin.HandlerFunc {
	return func(c *gin.Context) {
		//限定请求的微信小程序的appid
		appId := dao.Cfg.Server.AppId
		if appId != "" && dao.Cfg.Server.LimitReferer && dao.Cfg.Server.RunMode != "dev" {
			prefix := fmt.Sprintf("https://servicewechat.com/%v/", appId)
			if !strings.HasPrefix(strings.ToLower(c.Request.Referer()),prefix) { //c.Request.Referer()网络请求的来源 (返回请求的URL)
				Fail(c,400,"not found")
			}
		}
		token := c.Request.Header.Get("Authorization")//返回请求头中携带的token值
		version := c.Request.Header.Get("x-version")
		if token == "" {
			Fail(c,400,"未登陆或者非法登陆")
			return
		}
		j := NewJwt()
		// 解析token包含的信息
		claims,err := j.ParseToken(token)
		if err != nil {
			if err == TokenExpired {
				Fail(c,400,"授权已过期")
				return
			}
			Fail(c,400,err.Error())
			return
		}
		member := dao.MemberDao.Find(claims.MemberId)

	}
}